home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-30 | 6.6 KB | 319 lines | [TEXT/CWIE] |
- unit LeastSquares;
- {Contains the curve fitting routines based on the Simplex method described in the article " Fitting Curves to Data "}
- {in the May 1984 issue of Byte magazine, pages 340-362.}
-
- interface
-
- uses
- QuickDraw, Palettes, Printing, globals, Utilities, graphics;
-
-
- const
- nvpp = 2;
- maxn = 6;
- maxnp = 20;
- alpha = 1.0;
- beta = 0.5;
- gamma = 2.0;
- lw = 5;
- root2 = 1.414214;
- MaxError = 1e-7;
-
- type
- ColumnVector = array[1..maxnp] of extended;
-
- vector = array[1..maxn] of extended;
- datarow = array[1..nvpp] of extended;
- index = 0..255;
-
-
- var
- m, n: integer;
- done: boolean;
- maxx, maxy: extended;
- i, j: index;
- h, l: array[1..maxn] of index;
- np, npmax, niter, maxiter: integer;
- next, center, smean, error, maxerr, p, q, step: vector;
- simp: array[1..maxn] of vector;
- data: array[1..maxnp] of datarow;
- filename, newname: string;
- yoffset: integer;
-
-
- procedure DoSimplexFit (nStandards, nCoefficients: integer; xdata, ydata: ColumnVector; var Coefficients: CoefficientArray; var residuals: ColumnVector);
-
-
- implementation
-
-
- function f (p: vector; d: datarow): extended;
- var
- x, y, ex: extended;
- begin
- x := d[1];
- case info^.fit of
- StraightLine:
- f := p[1] + p[2] * x;
- Poly2:
- f := p[1] + p[2] * x + p[3] * x * x;
- Poly3:
- f := p[1] + p[2] * x + p[3] * x * x + p[4] * x * x * x;
- Poly4:
- f := p[1] + p[2] * x + p[3] * x * x + p[4] * x * x * x + p[5] * x * x * x * x;
- ExpoFit:
- f := p[1] * exp(p[2] * x);
- PowerFit:
- if x = 0.0 then
- f := 0.0
- else
- f := p[1] * exp(p[2] * ln(x)); {y=ax^b}
- LogFit:
- begin
- if x = 0.0 then
- x := 0.5;
- f := p[1] * ln(p[2] * x)
- end;
- RodbardFit:
- begin
- if x = 0.0 then
- ex := 0.0
- else
- ex := exp(ln(x / p[3]) * p[2]);
- y := p[1] - p[4];
- y := y / (1 + ex);
- f := y + p[4];
- end; {Rodbard fit}
- end; {case}
- end;
-
-
- procedure order;
- var
- i, j: index;
- begin
- for j := 1 to n do
- begin
- for i := 1 to n do
- begin
- if simp[i, j] < simp[l[j], j] then
- l[j] := i;
- if simp[i, j] > simp[h[j], j] then
- h[j] := i
- end
- end
- end;
-
-
- procedure sum_of_residuals (var x: vector);
-
- var
- i: index;
- begin
- x[n] := 0.0;
- for i := 1 to np do
- x[n] := x[n] + sqr(f(x, data[i]) - data[i, 2])
- end;
-
-
- procedure Initialize;
- var
- i, j: index;
- firstx, firsty, lastx, lasty, xmean, ymean, slope, yintercept: extended;
- begin
- firstx := data[1, 1];
- firsty := data[1, 2];
- lastx := data[np, 1];
- lasty := data[np, 2];
- xmean := (firstx + lastx) / 2.0;
- ymean := (firsty + lasty) / 2.0;
- if (lastx - firstx) <> 0.0 then
- slope := (lasty - firsty) / (lastx - firstx)
- else
- slope := 1.0;
- yintercept := firsty - slope * firstx;
- case info^.fit of
- StraightLine:
- begin
- simp[1, 1] := yintercept;
- simp[1, 2] := slope;
- end;
- Poly2:
- begin
- simp[1, 1] := yintercept;
- simp[1, 2] := slope;
- simp[1, 3] := 0.0;
- end;
- Poly3:
- begin
- simp[1, 1] := yintercept;
- simp[1, 2] := slope;
- simp[1, 3] := 0.0;
- simp[1, 4] := 0.0;
- end;
- Poly4:
- begin
- simp[1, 1] := yintercept;
- simp[1, 2] := slope;
- simp[1, 3] := 0.0;
- simp[1, 4] := 0.0;
- simp[1, 5] := 0.0;
- end;
- ExpoFit:
- begin
- simp[1, 1] := 0.1;
- simp[1, 2] := 0.01;
- end;
- PowerFit:
- begin
- simp[1, 1] := 0.0;
- simp[1, 2] := 1.0;
- end;
- LogFit:
- begin
- simp[1, 1] := 0.5;
- simp[1, 2] := 0.05;
- end;
- RodbardFit:
- begin
- simp[1, 1] := firsty;
- simp[1, 2] := 1.0;
- simp[1, 3] := xmean;
- simp[1, 4] := lasty;
- end;
- end;
- maxiter := 100 * m * m;
- n := m + 1;
- for i := 1 to m do
- begin
- step[i] := simp[1, i] / 2.0;
- if step[i] = 0.0 then
- step[i] := 0.01;
- end;
- for i := 1 to n do
- maxerr[i] := MaxError;
- sum_of_residuals(simp[1]);
- for i := 1 to m do
- begin
- p[i] := step[i] * (sqrt(n) + m - 1) / (m * root2);
- q[i] := step[i] * (sqrt(n) - 1) / (m * root2)
- end;
- for i := 2 to n do
- begin
- for j := 1 to m do
- simp[i, j] := simp[i - 1, j] + q[j];
- simp[i, i - 1] := simp[i, i - 1] + p[i - 1];
- sum_of_residuals(simp[i])
- end;
- for i := 1 to n do
- begin
- l[i] := 1;
- h[i] := 1
- end;
- order;
- maxx := 255;
- end;
-
-
- procedure new_vertex;
- var
- i: index;
- begin
- for i := 1 to n do
- simp[h[n], i] := next[i]
- end;
-
-
- procedure DoSimplexFit (nStandards, nCoefficients: integer; xdata, ydata: ColumnVector; var Coefficients: CoefficientArray; var residuals: ColumnVector);
- var
- i, j: integer;
- d: datarow;
- begin
- np := nStandards;
- m := nCoefficients;
- for i := 1 to np do
- begin
- data[i, 1] := xdata[i];
- data[i, 2] := ydata[i];
- end;
- Initialize;
- niter := 0;
- repeat
- done := true;
- niter := succ(niter);
- for i := 1 to n do
- center[i] := 0.0;
- for i := 1 to n do
- if i <> h[n] then
- for j := 1 to m do
- center[j] := center[j] + simp[i, j];
- for i := 1 to n do
- begin
- center[i] := center[i] / m;
- next[i] := (1.0 + alpha) * center[i] - alpha * simp[h[n], i]
- end;
- sum_of_residuals(next);
- if next[n] <= simp[l[n], n] then
- begin
- new_vertex;
- for i := 1 to m do
- next[i] := gamma * simp[h[n], i] + (1.0 - gamma) * center[i];
- sum_of_residuals(next);
- if next[n] <= simp[l[n], n] then
- new_vertex
- end
- else
- begin
- if next[n] <= simp[h[n], n] then
- new_vertex
- else
- begin
- for i := 1 to m do
- next[i] := beta * simp[h[n], i] + (1.0 - beta) * center[i];
- sum_of_residuals(next);
- if (next[n] <= simp[h[n], n]) then
- new_vertex
- else
- begin
- for i := 1 to n do
- begin
- for j := 1 to m do
- simp[i, j] := (simp[i, j] + simp[l[n], j]) * beta;
- sum_of_residuals(simp[i])
- end
- end
- end
- end;
- order;
- for j := 1 to n do
- begin
- if (simp[h[j], j] - simp[l[j], j]) = 0 then
- error[j] := 0
- else if simp[h[j], j] <> 0 then
- error[j] := (simp[h[j], j] - simp[l[j], j]) / simp[h[j], j]
- else
- error[j] := (simp[h[j], j] - simp[l[j], j]) / simp[l[j], j];
- if done then
- if abs(error[j]) > maxerr[j] then
- done := false
- end;
- until (done or (niter = maxiter));
- ShowMessage(concat('interations=', long2str(niter), crStr, 'max interations=', long2str(maxiter)));
- for i := 1 to n do
- begin
- smean[i] := 0;
- for j := 1 to n do
- smean[i] := smean[i] + simp[j, i];
- smean[i] := smean[i] / n;
- end;
- for i := 1 to m do
- Coefficients[i] := smean[i];
- for i := 1 to nstandards do
- begin
- d[1] := xdata[i];
- Residuals[i] := ydata[i] - f(smean, d);
- end;
- end;
-
-
- end.